/*********************************************
 *Flow control over WiFi and UART for ESP8266.
 *Author: openthings@163.com. 
 *copyright&GPL V2.
 *Last modified 2014-10-20.
 **********************************************/

#include "c_types.h"
#include "user_interface.h"
#include "xc_version.h"
#include "version.h"
#include "espconn.h"
#include "mem.h"
#include "xc.h"
#include "osapi.h"
#include "driver/uart.h"
#include "xc_cmd.h"
#include "xc_cmd_wifi.h"
#include "xc_cmd_tcp.h"
#include "xc_cmd_gpio.h"

#include "../tcpserver/wix_tcpserver.h"
#include "../tcpclient/wix_tcpclient.h"

#include "../udpserver/wix_udpserver.h"
#include "../udpclient/wix_udpclient.h"

#include "../dht22/dht22.h"

#define GET_ARRAY_LEN(array,len) {len = (sizeof(array) / sizeof(array[0]));}

/******************************************************
 *控制指令表。可以来自于串口或WiFi。
 *指令格式： @+CWJAP=apname,pwd
 ******************************************************/
cmd_functionType cmd_fun[xc_cmdNum]={
	{"@", 1, xc_cmd_Null},										//1-测试是否支持XCMD。
	{"@?", 2, xc_cmd_About},									//2-返回固件的信息。
	{"@+GMR", 5,xc_cmd_GMR},							//3-返回固件版本号。
	{"@+CHIPID",8,xc_cmd_CHIPID},						//7-是否回显。
	{"@+HEAP",6,xc_cmd_HEAP},							//7-是否回显。

	{"@+MAC?", 6,xc_cmd_MACQ},							//4-查询MAC地址。
	{"@+MAC", 5,xc_cmd_MAC},								//5-设置MAC地址。
	{"@+MACAP?", 8,xc_cmd_MACAPQ},				//4-查询AP MAC地址。
	{"@+MACAP", 7,xc_cmd_MACAP},					//5-设置AP MAC地址。
	{"@+PROMIS", 9,xc_cmd_PROMIS},				//5-设置混杂模式是否打开。

	{"@@", 2, xc_cmd_Chain},									//6-链接到串口控制外部设备。
	{"@E", 2, xc_cmd_setupE},								//7-是否回显。
	{"@+RST",5, xc_cmd_RST},								//8-系统重置。

	{"@+CWMODE?", 9, xc_cmd_CWMODEQ},		//9-返回WiFi的工作模式。
	{"@+CWMODE", 8, xc_cmd_CWMODE},			//10-设置WiFi的工作模式。
	{"@+CWCHANNEL?", 12, xc_cmd_CWCHANNELQ},	//11-返回WiFi的工作频道。
	{"@+CWCHANNEL", 11, xc_cmd_CWCHANNEL},			//12-设置WiFi的工作频道。

	{"@+CWLAP", 7, xc_cmd_CWLAP},					//13-扫描可用的热点。
	{"@+CWJAP?", 8, xc_cmd_CWJAPQ},					//14-设置接入点SSID和PWD。
	{"@+CWJAP", 7, xc_cmd_CWJAP},						//15-设置接入点SSID和PWD。
	{"@+CWCAP", 7,xc_cmd_CWCAP},					//16-根据当前AP的参数连接。
	{"@+CWQAP", 7,xc_cmd_CWQAP},					//16-退出当前AP的连接。
	
	{"@+CWSAP?", 8, xc_cmd_CWSAPQ},				//17-作为AP的参数查询。
	{"@+CWSAP", 7, xc_cmd_CWSAP},					//18-作为AP的参数设置。
	{"@+CWLIF", 7, xc_cmd_CWLIF},						//19-查看已接入设备的IP。

	{"@+CIP?", 6, xc_cmd_CIPQ},							//20-查询IP地址（STATION模式）。
	{"@+CIP", 5, xc_cmd_CIP},								//21-设置IP地址（STATION模式）。
	{"@+CIPAP?", 8, xc_cmd_CIPAPQ},					//22-查询softAP的IP地址（AP/STA+AP模式）。
	{"@+CIPAP", 7, xc_cmd_CIPAP},						//23-设置softAP的IP地址（AP/STA+AP模式）。

	{"@+CIPCLIENT?", 12, xc_cmd_CIPCLIENTQ},	//24-查看连接的客户端IP地址。
	{"@+CIPCLIENT", 11, xc_cmd_CIPCLIENT},		//25-建立TCP客户端连接到远端服务器。
	{"@+CIPCLOSE", 10, xc_cmd_CIPCLOSE},		//26-关闭到远端服务器的连接。

	{"@+CIPSTO?", 9, xc_cmd_CIPSTOQ},				//27-查询TCP服务器的超时时长。
	{"@+CIPSTO", 8, xc_cmd_CIPSTO},					//28-设置TCP服务器的超时时长。
	{"@+CIPSERVER?", 12,xc_cmd_CIPSERVERQ},	//29-建立TCP服务器。
	{"@+CIPSERVER", 11,xc_cmd_CIPSERVER},		//30-建立TCP服务器。
	{"@+CIPSCLOSE", 11,xc_cmd_CIPSCLOSE},		//31-关闭TCP服务器。

	{"@+CUDPCLIENT?", 13, xc_cmd_CUDPCLIENTQ},	//32-查看连接的客户端IP地址。
	{"@+CUDPCLIENT", 12, xc_cmd_CUDPCLIENT},		//33-建立TCP客户端连接到远端服务器。
	{"@+CUDPCLOSE", 11, xc_cmd_CUDPCLOSE},		//34-关闭到远端服务器的连接。

	{"@+CUDPSERVER?", 13,xc_cmd_CUDPSERVERQ},	//35-查询UDP服务器。
	{"@+CUDPSERVER", 12,xc_cmd_CUDPSERVER},		//36-建立UDP服务器。
	{"@+CUDPSCLOSE", 12,xc_cmd_CUDPSCLOSE},		//37-关闭UDP服务器。

	{"@+CGPIO?", 8,xc_cmd_CGPIOQ},					//38-GPIO查询。
	{"@+CGPIO", 7,xc_cmd_CGPIO},					//39-GPIO设置。
	{"@+CDHT22", 8,xc_cmd_CDHT22}//,					//39-GPIO设置。
		
	//{"+CIPMUX", 7, NULL, at_queryCmdCipmux, at_setupCmdCipmux, NULL},
	//{"+CIPMODE", 8, NULL, at_queryCmdCipmode, at_setupCmdCipmode, NULL},
	//{"+CIUPDATE", 9, NULL, NULL, NULL, at_exeCmdUpdate}
};

int8_t ICACHE_FLASH_ATTR dataStrCpy(void *pDest, const void *pSrc, int8_t maxLen)
{
	char *pTempD = pDest;
	const char *pTempS = pSrc;
	int8_t len;

	if(*pTempS != '\"')
	{
		return -1;
	}
	
	pTempS++;
	for(len=0; len<maxLen; len++)
	{
		if(*pTempS == '\"')
		{
			*pTempD = '\0';
			break;
		}
		else
		{
			*pTempD++ = *pTempS++;
		}
	}
	
	if (len == maxLen)
	{
		return -1;
	}
	return len;
}

/******************************************************
 *执行控制指令。可以来自于串口或WiFi。
 *指令格式： @+CWJAP=apname,pwd
 ******************************************************/
void xc_cmd_onCmd(char* pCMD)
{
	//过滤，解析出控制指令。
	char delims[] = "=";
	char *head = NULL;

	int16_t i,cmdLen;
	head = strtok( pCMD, delims );
	cmdLen = strlen(head);
	if (cmdLen == 1)		//only "@", just test.
	{
		xc_cmd_Null(0, NULL);
		return ;
	}
	
// 	if (cmdLen == 2)		//only "@", just test.
// 	{
// 		xc_cmd_Null(0, NULL);
// 		return ;
// 	}
	
	//继续查找参数。
	char * pParam = strtok(NULL, delims );
	//if (pParam==NULL){
	//		sendInfoAll("No param.\r\n");
	//		return;
	//}

	//char* temp[64];
	//os_sprintf(temp, "CMD: %s, PARAM: %s, LEN: %d\r\n",head,pParam,cmdLen);
	//sendInfo(temp);
	
	//查找命令并执行。
	//pCMD += cmdLen+1;
	//xc_cmdNum = len(cmd_fun);
	for (i=1; i<xc_cmdNum; i++) {
		if (cmdLen == cmd_fun[i].cmdLen)	{
			if (os_memcmp(head, cmd_fun[i].cmdName, cmdLen) == 0) {
				//sendInfo("EXEC: ");
				//sendInfo(cmd_fun[i].cmdName);
				//sendInfo("PARAM: ");
				//sendInfo(pCMD);
				cmd_fun[i].cmdFunc(i,pParam);	//Got:
				return;
			}
		}
	}
}

/*****************************************************
 * 指令系统运行测试。
 * 输入：@
 * 返回：OK
 *****************************************************/
void xc_cmd_Null(uint8_t id, char *pPara)
{
	sendInfoAll("OK\r\n");
}

/*****************************************************
 * 关于固件的信息。
 * 输入：@?
 * 返回：固件信息。
 *****************************************************/
void xc_cmd_About(uint8_t id, char *pPara)
{
	//链接到外部串口控制，暂未实现。
	sendInfoAll("XCMD Firmware.   By OpenThings.163.com.\r\n");
}

/*****************************************************
 * 显示模块的固件和SDK信息。
 * 输入：@E
 * 返回：版本信息。如，00180902
 *****************************************************/
void xc_cmd_GMR(uint8_t id, char *pPara)
{
	char temp[32];
	os_sprintf(temp,"\r\n%04X%06X\r\n", XC_VERSION, SDK_VERSION);
	sendInfoAll(temp);
	//at_backOk;	
}

/*****************************************************
 * 显示模块的芯片ID信息。
 * 输入：@+CHIPID
 * 返回：ID信息。
 *****************************************************/
void xc_cmd_CHIPID(uint8_t id, char *pPara)
{
	char temp[32];
	os_sprintf(temp,"\r\n%d\r\n", system_get_chip_id());
	sendInfoAll(temp);
}

/*****************************************************
 * 显示模块的内存信息。
 * 输入：@+HEAP
 * 返回：可用内存信息。
 *****************************************************/
void xc_cmd_HEAP(uint8_t id, char *pPara)
{
	char temp[32];
	os_sprintf(temp,"\r\n%d\r\n", system_get_free_heap_size());
	sendInfoAll(temp);
}

/*****************************************************
 * 显示模块的MAC地址信息。
 * 输入：
 * 返回：
 *****************************************************/
void xc_cmd_MACQ(uint8_t id, char *pPara)
{
	char temp[32];
	uint8_t mac[6];
	if (wifi_get_macaddr(STATION_IF,mac)==TRUE) {
		os_sprintf(temp,"STA MAC: %02x-%02x-%02x-%02x-%02x-%02x \r\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
		sendInfoAll(temp);
	} else {
		sendInfoAll("STA MAC: error.\r");
	}
	if (wifi_get_macaddr(SOFTAP_IF,mac)==TRUE) {
	os_sprintf(temp,"AP MAC: %02x-%02x-%02x-%02x-%02x-%02x \r\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);	
	sendInfoAll(temp);
	} else {
		sendInfoAll("AP MAC: error.\r\n");
	}	
}

/*****************************************************
 * 设置模块的MAC地址信息。
 * 输入：
 * 返回：
 *****************************************************/
void xc_cmd_MAC(uint8_t id, char *pPara)
{
	char temp[32];
	uint8_t mac[6];
	
	//区分，STA或AP模式，两个呢！
	//sofap_mac=pParam;
	if (wifi_set_macaddr(STATION_IF, mac)) {
		os_sprintf(temp,"SET MAC: %02x-%02x-%02x-%02x-%02x-%02x \r\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
		sendInfoAll(temp);
	} else {
		sendInfoAll("SET MAC:error.\r\n");
	}
}


/*****************************************************
 * 显示模块AP的MAC地址信息。
 * 输入：
 * 返回：
 *****************************************************/
void xc_cmd_MACAPQ(uint8_t id, char *pPara)
{
	char temp[32];
	uint8_t mac[6];
	if (wifi_get_macaddr(SOFTAP_IF,mac)==TRUE) {
		os_sprintf(temp,"AP MAC: %02x-%02x-%02x-%02x-%02x-%02x \r\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);	
		sendInfoAll(temp);
	} else {
		sendInfoAll("AP MAC:error.\r\n");
	}
}

/*****************************************************
 * 设置模块AP的MAC地址信息。
 * 输入：
 * 返回：
 *****************************************************/
void xc_cmd_MACAP(uint8_t id, char *pPara)
{
	char temp[32];
	uint8_t mac[6];
	
	//sofap_mac=pParam;
	if (wifi_set_macaddr(SOFTAP_IF, mac)==TRUE) {
		os_sprintf(temp,"SET MAC: %02x-%02x-%02x-%02x-%02x-%02x \r\n",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
		sendInfoAll(temp);
	} else {
		sendInfoAll("SET MAC:error.");
	}
}

/*****************************************************
 * 混杂模式打开或关闭。打开时可以使用sniffer功能。
 * 混杂模式打开使网卡可以收到其它网卡发的包，进行抓取。
 * 输入：
 * 返回：。
 *****************************************************/
void xc_cmd_PROMIS(uint8_t id, char *pPara)
{
	uint8 iPromis= atoi(pPara);
	if (iPromis==0) {
		wifi_promiscuous_enable(0);
		sendInfoAll("Promis Disable.");
	} else {
		wifi_promiscuous_enable(1);
		sendInfoAll("Promis Enable.");		
	}
	//安装回调函数。
	//Void wifi_set_promiscuous_rx_cb(wifi_promiscuous_cb_t cb)
}

/*****************************************************
 * 通过串口链接到外部运行的指令。比如，控制Arduino设备。
 * 输入：@@
 * 返回：由Arduino设备的固件返回。
 *****************************************************/
void xc_cmd_Chain(uint8_t id, char *pPara)
{
	//链接到外部串口控制，暂未实现。
	sendInfoAll("CMD Chains.");
}

/*****************************************************
 * 是否进行输入指令的回显。
 * 输入：@E
 * 返回：ECHO ON or ECHO OFF。
 *****************************************************/
void xc_cmd_setupE(uint8_t id, char *pPara)
{
	/*
	if(*pPara == '0'){
		echoFlag = FALSE;
	}
	else if(*pPara == '1'){
		echoFlag = TRUE;
	}  
	else  {
		at_backError;
		return;
	}
	at_backOk;
*/
}

/*****************************************************
 * 模块重置，重新初始化。
 * 输入：@E
 * 返回：启动信息。
 *****************************************************/
void xc_cmd_RST(uint8_t id, char *pPara) {
	sendInfoAll("OK.\r");
	system_restart();
}


